﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ZeroBug.EasyFlow.Core
{
    public class FlowBase
    {
        private int scanRate;
        protected FlowManager? _flowManager;
        private Thread? _flowThread;
        private Step? _currrentStep;
        private string _description;
        private List<Step> _steps;
        public string? Description
        {
            get => _description;
            set
            {
                _description = value;
                if (_flowThread != null)
                    _flowThread.Name = _description;
            }
        }
        public bool IsEnabled { get; set; }
        public bool IsBackground { get; set; }
        public Step EntranceStep { get; set; }
        public Step HomeEntranceStep { get; set; }
        [XmlIgnore]
        public FlowStatus Status { get; set; } = new FlowStatus();
        [XmlIgnore]
        public bool IsHomeFinish { get; set; }
        [XmlIgnore]
        public bool IsStepRun { get; set; }
        [XmlIgnore]
        public bool PauseFlag { get; set; } = true;
        public SerializableDictionary<string, Variable> Variables { get; set; }
        public FlowBase()
        {
            _flowThread = new Thread(flowMethod);
            _flowThread.IsBackground = true;
            this.IsEnabled = true;
            this.EntranceStep = new Step("root", "RootStep", this);
            this.HomeEntranceStep = new Step("home", "RootStep", this);
            this.Variables = new SerializableDictionary<string, Variable>();
            this._steps = new List<Step>();
            this._steps.Add(this.EntranceStep);
            this._steps.Add(this.HomeEntranceStep);
        }
        public FlowBase(string flowName)
            : this()
        {
            this.Description = flowName;
        }
        public FlowBase(string flowName, FlowManager flowmanager)
            : this(flowName)
        {
            this._flowManager = flowmanager;
            this._flowManager.Flows.Add(this.Description, this);
        }

        #region 流程控制
        /// <summary>
        /// 只在初始化是调用一次
        /// </summary>
        public void Open()
        {
            EntranceStep.InitializeSteps(_flowManager.GetStepOperators(), this);
            HomeEntranceStep.InitializeSteps(_flowManager.GetStepOperators(), this);

            EntranceStep.RegisterVariables();
            //Home只需要运行一次
            this.Status = FlowStatus.Created;
            _flowThread.Start();
        }
        /// <summary>
        /// 只在系统关闭是调用
        /// </summary>
        public void Close()
        {
            _flowThread.Abort();
            this.Status = FlowStatus.Closed;
        }
        public void Compile(out string errInfo)
        {
            EntranceStep.Compile(out errInfo);
        }
        public void Prepare(out string errInfo)
        {
            EntranceStep.Prepare(out errInfo);
        }
        public bool CanFlowContinue()
        {
            WaitForStart();
            if (IsBreak()) return false;
            return true;
        }
        public void WaitForStart()
        {
            if (PauseFlag)
                Status = FlowStatus.Paused;
            if(this._flowManager.WaitForStart(this))
                Status = FlowStatus.Running;
            else
                Status = FlowStatus.Stopped;
        }
        public bool IsBreak()
        {
            return _flowManager.IsBreak();
        }
        public void Init(out string errInfo)
        {
            errInfo = "";
            Status = FlowStatus.Init;
            //TODO

            //if success
            _currrentStep = EntranceStep;
        }
        public bool PreStartCheck()
        {
            return true;
        }
        public void OnStop()
        {

        }
        public string CreateStepName(string stepOperatorName)
        {
            string name = "";
            for (int i = 0; i < 999999; i++)
            {
                name = $"{stepOperatorName}{i}";
                if (!_steps.Any(s => IsNameExist(s, name)))
                    break;
            }
            return name;
        }
        public bool IsNameExist(Step s, string name)
        {
            if (s.Description.Equals(name))
                return true;
            foreach (var item in s.Children)
            {
                if (IsNameExist(item, name))
                    return true;
            }
            return false;
        }
        #endregion

        #region 信号操作
        public bool WaitForSignal(string fromFlowName, string signalName)
        {
            //卡住等待信号，两种情况会继续：1.收到信号 2.强制跳过
            return this._flowManager.WaitSignal(fromFlowName, signalName);
        }
        public bool CheckSignal(string fromFlowName, string signalName)
        {
            return this._flowManager.GetSignal(fromFlowName, signalName).GetStatus();
        }
        public void RegisterSignal(string signalName, bool initState = false)
        {
            this._flowManager.RegisterSignal(Description, signalName, initState);
        }
        public void SetSignal(string signalName)
        {
            this._flowManager.SetSignal(Description, signalName);
        }
        #endregion
        private async void flowMethod()
        {
            string errInfo = "";

            while (true)
            {
                if (IsEnabled)
                {
                start:
                    //判断是否结束程序或暂停,暂停的话 流程停在这里  停止的话，流程从entrance step开始
                    if (!CanFlowContinue())
                    {
                        while (this.Status != FlowStatus.Stopped)
                        {
                            Thread.Sleep(20);
                        }
                        Thread.Sleep(100);
                        _currrentStep = Status == FlowStatus.Home ? HomeEntranceStep : EntranceStep;
                        _currrentStep.OnStepPrepare2Run?.Invoke();
                        goto start;
                    }
                    if (IsEnabled)
                    {
                        //运行本步
                        StepResult result = _currrentStep.Run(out errInfo);
                        switch (result)
                        {
                            case StepResult.Success:
                                _currrentStep.IsRunSuccess = true;
                                break;
                            case StepResult.Failure:
                                //异常处理
                                Status = FlowStatus.Warning;
                                this._flowManager.Pause();
                                Thread.Sleep(10);
                                goto start;
                            case StepResult.Break:
                                goto resume;
                        }
                        _flowManager.GetLogger().Log(LogSource.App, $"{_currrentStep.Description} just run...", MessageLevel.Log);
                        if (Status == FlowStatus.Home)
                            _currrentStep = _currrentStep!.GetNext() ?? HomeEntranceStep;
                        else
                            _currrentStep = _currrentStep.GetNext() ?? EntranceStep;
                        resume:
                        //如果不为条件节点 才进行单步运行，否则直接过去
                        if (IsStepRun && !_currrentStep.IsConditionNode)
                        {
                            IsStepRun = false;
                            this.PauseFlag = true;
                        }
                        _currrentStep.OnStepPrepare2Run?.Invoke();
                    }
                    else
                        this.Status = FlowStatus.Stopped;
                }
                else
                    this.Status = FlowStatus.Stopped;
                //扫描周期
                Thread.Sleep(scanRate);
            }
        }
        public void SetFlowManager(FlowManager flowManager)
        {
            this._flowManager = flowManager;
        }
        public FlowManager? GetFlowManager()
        {
            return this._flowManager;
        }
        public void AddStep(string stepName, 
                            string operatorName, 
                            Step fatherStep, 
                            SerializableDictionary<string, VariableExpression> parameters,
                            List<VariableJudge> conditions)
        {
            if (this._steps.FirstOrDefault(s => s.Description.Equals(stepName)) != null)
                throw new Exception("已存在同名变量");
            Step step = new Step(stepName, operatorName, this);
            step.Parameters = parameters;
            step.Conditions = conditions;

            #region 根据Conditions的个数来决定是否提前增加子节点
            if (step.Conditions != null && step.Conditions.Count > 0)
            {
                if (step.Conditions.Count == 1)
                {
                    Step ss = new Step($"{stepName}.满足", "GroupStep", this);
                    ss.Alias = "满足";
                    ss.IsConditionNode = true;
                    ss.InitializeStep(_flowManager.GetStepOperators(), this);
                    ss.RegisterVariables();
                    step.AddChildren(ss);
                    _steps.Add(ss);

                    ss = new Step($"{stepName}.不满足", "GroupStep", this);
                    ss.Alias = "不满足";
                    ss.IsConditionNode = true;
                    ss.InitializeStep(_flowManager.GetStepOperators(), this);
                    ss.RegisterVariables();
                    step.AddChildren(ss);
                    _steps.Add(ss);
                }
                else
                {
                    int index = 0;
                    foreach (var item in step.Conditions)
                    {
                        Step ss = new Step($"{stepName}.条件{index}", "GroupStep", this);
                        ss.Alias = item.Alias == null ? $"条件{index}" : $"条件{index}-{item.Alias}";
                        ss.IsConditionNode = true;
                        ss.Tip = item.ToString();
                        ss.InitializeStep(_flowManager.GetStepOperators(), this);
                        ss.RegisterVariables();
                        step.AddChildren(ss);
                        _steps.Add(ss);
                        index++;
                    }
                }
            }
            #endregion

            step.InitializeStep(this._flowManager.GetStepOperators(), this);
            step.RegisterVariables();
            fatherStep.AddChildren(step);

            _steps.Add(step);
        }
        public void AddStep(Step step, Step fatherStep, bool isInsert = false, int insertIndex = 0)
        {
            step.Parameters = step.GetOperator().GetParametersAndConditions().Item1;
            step.Conditions = step.GetOperator().GetParametersAndConditions().Item2;

            #region 根据Conditions的个数来决定是否提前增加子节点
            if (step.Conditions != null && step.Conditions.Count > 0)
            {
                if (step.Conditions.Count == 1)
                {
                    Step ss = new Step($"{step.Description}.满足", "GroupStep", this);
                    ss.Alias = "满足";
                    ss.IsConditionNode = true;
                    ss.InitializeStep(_flowManager.GetStepOperators(), this);
                    ss.RegisterVariables();
                    step.AddChildren(ss);
                    _steps.Add(ss);

                    ss = new Step($"{step.Description}.不满足", "GroupStep", this);
                    ss.Alias = "不满足";
                    ss.IsConditionNode = true;
                    ss.InitializeStep(_flowManager.GetStepOperators(), this);
                    ss.RegisterVariables();
                    step.AddChildren(ss);
                    _steps.Add(ss);
                }
                else
                {
                    int index = 0;
                    foreach (var item in step.Conditions)
                    {
                        Step ss = new Step($"{step.Description}.条件{index}", "GroupStep", this);
                        ss.Alias = item.Alias == null ? $"条件{index}" : $"条件{index}-{item.Alias}";
                        ss.IsConditionNode = true;
                        ss.Tip = item.ToString();
                        ss.InitializeStep(_flowManager.GetStepOperators(), this);
                        ss.RegisterVariables();
                        step.AddChildren(ss);
                        _steps.Add(ss);
                        index++;
                    }
                }
            }
            #endregion

            step.InitializeStep(this._flowManager.GetStepOperators(), this);
            step.RegisterVariables();
            if (isInsert)
                fatherStep.InsertChildren(step, insertIndex);
            else
                fatherStep.AddChildren(step);

            _steps.Add(step);
        }
        public void DeleteStep(Step step)
        {
            //注销变量
            step.UnRegisterVariables();
            //父步骤删掉本步
            step.GetParent().Children.Remove(step);
            //flow所有步删掉本步
            _steps.Remove(step);
            //若有子步，递归删除子步
            foreach (var item in step.Children)
            {
                DeleteStep(item);
            }
        }
        public Step? GetStep(string stepName)
        {
            return this._steps.FirstOrDefault(s => s.Description == stepName);
        }
        public List<Step> GetSteps() => _steps;
             
        public void AddVariable(Variable variable)
        {
            if (Variables.ContainsKey($"{this.Description}.{variable.Name}"))
                Variables[$"{this.Description}.{variable.Name}"] = variable;
            else
                Variables.Add($"{this.Description}.{variable.Name}", variable);
            variable.Name = $"{this.Description}.{variable.Name}";
            _flowManager.VariableManager.AddVariable(variable, VariableFrom.Local);
        }
        public void LoadLocalVariables()
        {
            foreach (var item in Variables)
            {
                item.Value.LoadFromOriginalValue();
                _flowManager.VariableManager.AddVariable(item.Value, VariableFrom.Local);
            }
        }
        public void ResetVariables()
        {
            foreach (var item in Variables)
            {
                item.Value.Reset();
            }
        }
    }
}
